﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Models;
using System.IO;

namespace SuperQuery.UserControls
{
    /// <summary>
    /// Interaction logic for QueryTab.xaml
    /// </summary>
    public partial class QueryTab : UserControl, Views.IQueryView
    {
        /// <summary>
        /// Initialise a Query Tab
        /// </summary>
        /// <param name="parentPresenter">The presenter of the parent window for this tab</param>
        public QueryTab(Presenters.MainWindowPresenter parentPresenter)
        {
            InitializeComponent();

            // Set up presenter
            m_Presenter = new Presenters.QueryTabPresenter(this, parentPresenter);

            // Populate the list of avaialble plugins for the database list filter
            m_Presenter.PopulateAvailablePlugins();
        }

        /// <summary>
        /// The query that is currently loaded into the view
        /// </summary>
        public Query LoadedQuery
        {
            get;
            set;
        }

        /// <summary>
        /// Whether of not the query has been modified since it was loaded or saved into the view
        /// </summary>
        public bool IsDirty
        {
            get;
            set;
        }

        /// <summary>
        /// Whether this query view has been selected to have its contents saved, used by the ISaveItem view that is displayed
        /// when the application is shut down
        /// </summary>
        public bool SelectedForSaving
        {
            get;
            set;
        }

        /// <summary>
        /// The name that the query is saved under
        /// </summary>
        public string QueryName
        {
            get
            {
                return (string)GetValue(QueryNameProperty);
            }
            set
            {
                SetValue(QueryNameProperty, value);
            }
        }

        /// <summary>
        /// The currently selected and displayed canCloseApplication set
        /// </summary>
        public QueryResult SelectedResult
        {
            get
            {
                return (QueryResult)GetValue(SelectedResultProperty);
            }
            set
            {
                SetValue(SelectedResultProperty, value);
            }
        }

        /// <summary>
        /// The currently selected database
        /// </summary>
        public Database SelectedDatabase
        {
            get
            {
                // Get the selected item (if any) out of the databases grid and convert it to a Database model
                Database result = null;
                if ((grdDatabases.SelectedItem != null) && (grdDatabases.SelectedItem is Database))
                {
                    result = (Database)grdDatabases.SelectedItem;
                }

                return result;
            }
            set
            {
                // Does the supplied database exist in the list of databases
                if (DatabaseList.Contains(value))
                {
                    // Yes it does so set it as the selected item
                    grdDatabases.SelectedItem = value;
                }
            }
        }

        /// <summary>
        /// List of databases currently loaded
        /// </summary>
        public List<Database> DatabaseList
        {
            get;
            set;
        }

        /// <summary>
        /// List of databases currently displayed in the Query Tab
        /// </summary>
        public List<Database> DisplayedDatabases
        {
            get
            {
                return (List<Database>)GetValue(DisplayedDatabasesProperty);
            }
            set
            {
                SetValue(DisplayedDatabasesProperty, value);
            }
        }

        /// <summary>
        /// The name of the currently loaded database list
        /// </summary>
        public string DatabaseListName
        {
            get;
            set;
        }

        /// <summary>
        /// If this is true then the database list has been updated and not saved
        /// </summary>
        public bool IsListDirty
        {
            get;
            set;
        }

        /// <summary>
        /// When this is true the user can edit the database list and the query itself
        /// </summary>
        /// <remarks>This is used to lock certain parts of the interface when the user is running a query</remarks>
        public bool EditorEnabled
        {
            get
            {
                return (bool)GetValue(EditorEnabledProperty);
            }
            set
            {
                SetValue(EditorEnabledProperty, value);
            }
        }

        /// <summary>
        /// Text to display in the status area
        /// </summary>
        public string Status
        {
            get
            {
                return (string)GetValue(StatusProperty);
            }
            set
            {
                SetValue(StatusProperty, value);
            }
        }

        /// <summary>
        /// When a query batch is running, how far through the process we have got
        /// </summary>
        public int Progress
        {
            get
            {
                return (int)GetValue(ProgressProperty);
            }
            set
            {
                SetValue(ProgressProperty, value);
            }
        }

        /// <summary>
        /// Refrsh the items in the data grid
        /// </summary>
        public void RefreshDataGrid()
        {
            if ((DisplayedDatabases != null) && (DisplayedDatabases.Count > 0))
            {
                // First get the items and make sure all edits etc are committed
                IEditableCollectionView items = grdDatabases.Items;
                items.CommitEdit();

                // Refresh the items
                grdDatabases.Items.Refresh();
            }
        }

        /// <summary>
        /// A dictionary of server plugins to use in the filter options
        /// </summary>
        public Dictionary<Guid, string> AvailablePlugins
        {
            get
            {
                return (Dictionary<Guid, string>)GetValue(AvailablePluginsProperty);
            }
            set
            {
                SetValue(AvailablePluginsProperty, value);
            }
        }

        /// <summary>
        /// Contains the text filter to apply to the database/server name
        /// </summary>
        public string DatabaseNameFilter
        {
            get
            {
                return (string)GetValue(DatabaseNameFilterProperty);
            }
            set
            {
                SetValue(DatabaseNameFilterProperty, value);
            }
        }


        /// <summary>
        /// Whether or not to filter for databases that have successfull queries against them
        /// </summary>
        public bool SuccessfullQueryFilter
        {
            get
            {
                return (bool)GetValue(SuccessfullQueryFilterProperty);
            }
            set
            {
                SetValue(SuccessfullQueryFilterProperty, value);
            }
        }

        /// <summary>
        /// Whether or not the filter is currently applied to the database list
        /// </summary>
        public bool FilterApplied
        {
            get
            {
                return (bool)GetValue(FilterAppliedProperty);
            }
            set
            {
                SetValue(FilterAppliedProperty, value);
            }
        }

        /// <summary>
        /// The currently selected plug in ID
        /// </summary>
        public Guid SelectedPluginID
        {
            get
            {
                Guid selectedID = Guid.Empty;
                if ((cboPlugins.SelectedItem != null) && (cboPlugins.SelectedItem is KeyValuePair<Guid, string>))
                {
                    KeyValuePair<Guid, string> selectedItem = (KeyValuePair<Guid, string>)cboPlugins.SelectedItem;
                    selectedID = selectedItem.Key;
                }

                return selectedID;
            }
            set
            {
                if (AvailablePlugins.ContainsKey(value))
                {
                    cboPlugins.SelectedItem = new KeyValuePair<Guid, string>(value, AvailablePlugins[value]);
                }
            }
        }

        /// <summary>
        /// When the database selection is changed update the selected results set for the currently displayed
        /// view
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void grdDatabases_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
        {
            if ((grdDatabases.SelectedItem != null) && (grdDatabases.SelectedItem is Database))
            {
                // Convert the selected item into a Database and update the SelectedResult property
                Database selectedDb = (Database)grdDatabases.SelectedItem;
                SelectedResult = selectedDb.Result;
            }
        }

        /// <summary>
        /// When the Edit button is clicked for a particular database, show the properties for that database
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void btnEditDB_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.EditSelectedDatabase();
        }

        /// <summary>
        /// When space bar is pressed, toggle the selected status the selected database
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void grdDatabases_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Space)
            {
                m_Presenter.ToggleSelectedDatabase();
            }
        }

        /// <summary>
        /// Event raised when one of the database list toolbar buttons is pressed
        /// </summary>
        /// <param name="buttonPressed">The button that has been pressed</param>
        private void dbListToolBar_ToolBarOperation(ToolBars.ToolBarButtons buttonPressed)
        {
            ToolBarFunction(buttonPressed);
        }

        /// <summary>
        /// Event raised when one of the Query Toolbar buttons is pressed
        /// </summary>
        /// <param name="buttonPressed">The buttons that was pressed</param>
        private void dbQueryToolBar_ToolBarOperation(ToolBars.ToolBarButtons buttonPressed)
        {
            ToolBarFunction(buttonPressed);
        }

        /// <summary>
        /// Decide what to do based on the supplied tool bar button
        /// </summary>
        /// <param name="buttonPressed">The tool bar button that was pressed</param>
        private void ToolBarFunction(ToolBars.ToolBarButtons buttonPressed)
        {
            switch (buttonPressed)
            {
                case SuperQuery.UserControls.ToolBars.ToolBarButtons.AddDatabase:
                {
                    // Add a database to the list
                    m_Presenter.AddDatabases();
                    break;
                }
                case SuperQuery.UserControls.ToolBars.ToolBarButtons.RemoveDataBase:
                {
                    // Remove a database from the list
                    m_Presenter.RemoveDatabases();
                    break;
                }
                case SuperQuery.UserControls.ToolBars.ToolBarButtons.SelectAll:
                {
                    // Select all databases
                    m_Presenter.SelectAll();
                    break;
                }
                case SuperQuery.UserControls.ToolBars.ToolBarButtons.SelectFailures:
                {
                    // Select failures
                    m_Presenter.SelectFailure();
                    break;
                }
                case SuperQuery.UserControls.ToolBars.ToolBarButtons.SelectSuccesses:
                {
                    // Select Successes
                    m_Presenter.SelectSuccess();
                    break;
                }
                case SuperQuery.UserControls.ToolBars.ToolBarButtons.InvertSelection:
                {
                    // Invert the current selection
                    m_Presenter.InvertSelection();
                    break;
                }
                case SuperQuery.UserControls.ToolBars.ToolBarButtons.RunAll:
                {
                    // Run the query against all databases
                    m_Presenter.RunQueryAll();
                    break;
                }
                case SuperQuery.UserControls.ToolBars.ToolBarButtons.RunSelected:
                {
                    // Run the query against selected databases
                    m_Presenter.RunQuerySelected();
                    break;
                }
                case SuperQuery.UserControls.ToolBars.ToolBarButtons.Stop:
                {
                    // Stop the currently running query (if any)
                    m_Presenter.StopQuery();
                    break;
                }
            }
        }

        /// <summary>
        /// When the text is altered by the user, change the IsDirty flag to true
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void txtQuery_TextChanged(object sender, TextChangedEventArgs e)
        {
            IsDirty = true;
        }

        /// <summary>
        /// The user wants to apply a filter
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void btnApplyFilter_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.ApplyDBListFilter();
        }

        /// <summary>
        /// The user wants to remove the filter
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void btnRemoveFilter_Click(object sender, RoutedEventArgs e)
        {
            m_Presenter.RemoveDBListFilter();
        }

        /// <summary>
        /// Event raised when the user control is loaded. Carry out work that cannot be done in the constructor as we need to
        /// control to be fully loaded first
        /// </summary>
        /// <param name="sender">Who raised the event</param>
        /// <param name="e">Details about the event</param>
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            // Set default plug in filter
            SelectedPluginID = Guid.Empty;
        }

        /// <summary>
        /// Using a DependencyProperty as the backing store for QueryName.  This enables animation, styling, binding, etc...
        /// </summary>
        private static readonly DependencyProperty QueryNameProperty =
            DependencyProperty.Register("QueryName", typeof(string), typeof(QueryTab), new UIPropertyMetadata(string.Empty));

        /// <summary>
        /// Using a DependencyProperty as the backing store for SelectedResult.  This enables animation, styling, binding, etc...
        /// </summary>
        private static readonly DependencyProperty SelectedResultProperty =
            DependencyProperty.Register("SelectedResult", typeof(QueryResult), typeof(QueryTab), new UIPropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for EditorEnabled.  This enables animation, styling, binding, etc...
        /// </summary>
        private static readonly DependencyProperty EditorEnabledProperty =
            DependencyProperty.Register("EditorEnabled", typeof(bool), typeof(QueryTab), new UIPropertyMetadata(true));

        /// <summary>
        /// Using a DependencyProperty as the backing store for Progress.  This enables animation, styling, binding, etc...
        /// </summary>
        private static readonly DependencyProperty ProgressProperty =
            DependencyProperty.Register("Progress", typeof(int), typeof(QueryTab), new UIPropertyMetadata(0));

        /// <summary>
        /// Using a DependencyProperty as the backing store for Status.  This enables animation, styling, binding, etc...
        /// </summary>
        private static readonly DependencyProperty StatusProperty =
            DependencyProperty.Register("Status", typeof(string), typeof(QueryTab), new UIPropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for AvailablePlugins.  This enables animation, styling, binding, etc... 
        /// </summary>
        private static readonly DependencyProperty AvailablePluginsProperty =
            DependencyProperty.Register("AvailablePlugins", typeof(Dictionary<Guid, string>), typeof(QueryTab), new UIPropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for DisplayedDatabases.  This enables animation, styling, binding, etc... 
        /// </summary>
        private static readonly DependencyProperty DisplayedDatabasesProperty =
            DependencyProperty.Register("DisplayedDatabases", typeof(List<Database>), typeof(QueryTab), new UIPropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for SuccessfullQueryFilter.  This enables animation, styling, binding, etc... 
        /// </summary>
        private static readonly DependencyProperty SuccessfullQueryFilterProperty =
            DependencyProperty.Register("SuccessfullQueryFilter", typeof(bool), typeof(QueryTab), new UIPropertyMetadata(false));

        /// <summary>
        /// Using a DependencyProperty as the backing store for DatabaseNameFilter.  This enables animation, styling, binding, etc... 
        /// </summary>
        private static readonly DependencyProperty DatabaseNameFilterProperty =
            DependencyProperty.Register("DatabaseNameFilter", typeof(string), typeof(QueryTab), new UIPropertyMetadata(null));

        /// <summary>
        /// Using a DependencyProperty as the backing store for FilterApplied.  This enables animation, styling, binding, etc...
        /// </summary>
        private static readonly DependencyProperty FilterAppliedProperty =
            DependencyProperty.Register("FilterApplied", typeof(bool), typeof(QueryTab), new UIPropertyMetadata(false));

        /// <summary>
        /// The presenter for the query tab
        /// </summary>
        private Presenters.QueryTabPresenter m_Presenter;
    }
}
